#include<iostream>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
 #include <sys/stat.h>
 #include <fcntl.h>

extern char** environ;


#define  NONE -1
#define  IN_RDIR 0 //输入
#define  OUT_RDIR 1//stdout
#define  APPEND_RDIR 2//stderr


char commandline[1024];//命令行
char *argv[32];//参数表
char pwd[1024];//路径长
char myenv[10][10];//环境变量表
int count=0;
int lastcode=0;//退出码

char * rdirfilename=NULL; //重定向的文件
int rdir =NONE;

const char* getusrname()
{ 
  const  char* str=getenv("USER");
 return str;
}

const char* gethostname()
{
     return getenv("HOSTNAME");
}

void getpwd()
{
  getcwd(pwd,sizeof(pwd));//是一个接口函数，将路径写到pwd里面
}

void checkdir(char * cmd)
{
  char *pos =cmd;
  while(*pos)
  {
    if(*pos=='>')
    {
        if(*(pos+1)=='>')//'>>'
        {
           *(pos++)='\0';
           *(pos++)='\0';
          while(*pos==' ') pos++;

          rdirfilename=pos;
          rdir = APPEND_RDIR;
          break;
        }
        else //'>'
        {
         *(pos++)='\0';                                                                                                                  
       while(*pos==' ') pos++;
       rdirfilename=pos;
       rdir=OUT_RDIR;
        }

    }
    else if(*pos=='<')
    {
       *pos='\0';
        pos++;
        while(*pos==' ') pos++;
        
        rdirfilename=pos;
        rdir=IN_RDIR;
         break;
    }
    else{}

    pos++;
   }   
  
}

void interact(char* cline,int size)//输出命令行
{
  getpwd();
 printf("[%s@%s%s]#  " ,getusrname(),gethostname(),pwd);
 
 char *s=fgets(cline,size,stdin);//输入指令，有可能什么也没有输入直接回车

 assert(s);
 (void)s;
 
 //”abcd\n\0" 
 cline[strlen(cline)-1]='\0';//原来\n，在输入的时候也会加入到字符串中;
  
   checkdir(cline);//检查重定向
}

int splitstring(char * cline,char *_argv[])
{
 int i=0;
 argv[i++]=strtok(cline," ");//字符串分割

 while(_argv[i++]=strtok(NULL," "));//如果截取失败就会返回NULL,正好是参数表尾;
 
 return i-1; //含回指令的参数个数。NULL不算
}


int buildCommand(char*_argv[],int _argc)
{

  if(_argc==2&&strcmp(_argv[0],"cd")==0)
  {
    chdir(argv[1]);//改变当前进程的路径，但是并不影响环境变量当中的路径
    getpwd();
    sprintf(getenv("PWD"),"%s",pwd);
    return 1;
  }
  else if(_argc==2&&strcmp(_argv[0],"export")==0)
  {
      strcpy(myenv[count],_argv[1]);
     
      putenv(myenv[count++]);
     
      return 1;
  }
  else if(_argc==2&&strcmp(_argv[0],"echo")==0)
  {
   if(strcmp(_argv[1],"$?")==0)
   {

     printf("%d\n",lastcode);
     lastcode=0;//查看完后置为0;
   }
   else if(*_argv[1]=='$')
   {
     char* val=getenv(_argv[1]+1);
     if(val) printf("%s\n",val);
   }
   else printf("%s\n",_argv[1]);
   return 1;
  }

  if(strcmp(_argv[0],"ls")==0)
  { 
    _argv[_argc++]="--color=auto";
    _argv[_argc]=NULL;
   // return 1;

  }

 return 0;
}

void NormalExcute(char* _argv[])
 {
  pid_t id=fork();
  if(id<0)
  {
    perror("fork");
    return ;
  }
  else if(id==0)
  {
    int fd=0;
    if(rdir==IN_RDIR)
    {
      fd=open(rdirfilename,O_RDONLY);
      dup2(fd ,0);
    }
    else if(rdir==OUT_RDIR)
    {
      fd=open(rdirfilename,O_CREAT|O_WRONLY|O_TRUNC,0666);
      dup2(fd,1);
    }
    else if(rdir==APPEND_RDIR)
    {
      fd=open(rdirfilename, O_CREAT|O_WRONLY|O_APPEND,0666);
      dup2(fd,1);
    }

    execvp(_argv[0],_argv);
    exit(1);
  }
  else 
  {
    int status=0;
    pid_t rid=waitpid(id,&status,0);
  
    //正常含回子进程的PID
  
    if(rid==id)
    {
      lastcode=WEXITSTATUS(status);
    }
  }
}


int main()
{
 
  while(1)
  {

    rdirfilename=NULL;
    rdir=NONE;    
 interact(commandline,sizeof(commandline));
 
 int argc=splitstring(commandline,argv);
 
 if(argc==0) continue;
 
 //for(int i=0;i<argc;i++) printf("argv[%d]:%s\n",i,argv[i]);

  int n=buildCommand(argv,argc);

  if(!n) NormalExcute(argv);
  
  }
  return 0;
}
